/*
 * @Description: 路由前置守卫
 * @Version: 1.0
 * @Autor: chen_yt
 * @Date: 2022-03-09 14:34:47
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2022-08-05 09:42:03
 */
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import store from '@/store'
import { localRoute } from '@/config'
import { getLocalRoutes, getUserRoutes } from '@/utils/route'
import { checkPwdStatus } from '@/utils/password'
import storage from '@/utils/storage'
import Vue from 'vue'


NProgress.configure({ showSpinner: false }) // NProgress Configuration



export class GuardsList {
    constructor() {
        this.strateges = {
            'normal': (to, from, next) => { return new normalBeforeGuards(to, from, next) },
            'mainapp': (to, from, next) => { return new mainappBeforeGuards(to, from, next) },
            'subapp': (to, from, next) => { return new subappBeforeGuards(to, from, next) },
            'inqiankun': (to, from, next) => { return new inqiankunBeforeGuards(to, from, next) },
        }
    }
    getGuard (name, to, from, next) {
        return this.strateges[name].call(null, to, from, next)
    }

}

/**
 * @description: 路由守卫基类
 *               包括基础跳转及动态加载路由
 *               
 */
class normalBeforeGuards {
    constructor(to, from, next) {
        this.to = to
        this.from = from
        this.next = next
    }
    /**
       * @description: 对路由进行重定向
       *               添加next()钩子后返回true，否则返回false
       * @return {Boolean} result
       */
    routeRedirect () {
        return false
    }

    /**
      * @description: routeRedirect未添加next()钩子时
      *               需要调用该方法解析路由
      */
    routeResolve () {
        this.routeMatch().then(res => {
            if (!res) {
                this.next('/403')
            }
        })
    }

    /**
       * @description: 对路由进行解析
       *               添加next()钩子后返回Promise.resolve(true)，否则返回Promise.resolve(false)              
       * @return {Promise} 
       */
    async routeMatch () {
        //全屏路由匹配成功时可直接放过
        if (this.to.matched?.length > 0 && this.to.meta?.config?.includes('fullScreen')) {
            this.next()
            return true
        }

        storage.set('redirectUrl', this.to.fullPath)

        //已加载路由的情况
        if (store.state.routes.length > 0) {
            if (this.to.matched?.length > 0) {
                this.next()
                return true
            }
            return false
        }
        //加载本地路由
        if (localRoute) {
            let result = await getLocalRoutes()
            if (!result) {
                return false
            }
            this.next({ ...this.to, replace: true })
            return true
        }
        //加载线上路由
        let result = await getUserRoutes()
        if (!result) {
            return false
        }

        //校验密码
        //let status = await checkPwdStatus()
        // let status = true
        // if (status) {
        //   this.next({ path: status, replace: true })
        //   return true
        // }


        this.next({ ...this.to, replace: true })
        return true
    }
}

/**
 * @description: 主应用中
 *               发现路由query参数带有keepOrigin时去除
 * 
 */
class mainappBeforeGuards extends normalBeforeGuards {
    routeRedirect () {
        if (this.to.query?.keepOrigin) {
            let query = this.to.query
            delete query.keepOrigin
            this.next({ path: this.to.path, query: query, params: this.to.params, meta: this.to.meta, replace: true })
            return true
        }
        return super.routeRedirect()
    }
}

/**
 * @description: 子应用模式下 
 *               有keepOringin参数时，重定向到不含/sub_app_xx前缀的路由
 *               无keepOringin参数时，重定向到含有/sub_app_xx前缀的路由
 */
class subappBeforeGuards extends normalBeforeGuards {
    routeRedirect () {
        let prefix = Vue.prototype.$appBasePath

        if (this.to.meta?.keepOrigin || this.to.query?.keepOrigin) {
            if (this.to.path.includes(prefix)) {
                this.next({ path: this.to.path.replace(prefix, ''), query: this.to.query, params: this.to.params, meta: this.to.meta, replace: true })
                return true
            }
            else {
                return super.routeRedirect()
            }
        }

        if (!this.to.path.includes(prefix)) {
            this.next({ path: prefix + this.to.path, query: this.to.query, params: this.to.params, meta: this.to.meta, replace: true })
            return true
        }

        return super.routeRedirect()
    }
}

/**
 * @description: qiankun环境下
 *               路由匹配失败时，去掉/sub_app_xx前缀，让主应用来处理这个路由
 */
class inqiankunBeforeGuards extends subappBeforeGuards {
    routeRedirect () {
        return super.routeRedirect()
    }
    routeResolve () {
        this.routeMatch().then(res => {
            console.log(res)
            if (!res) {
                NProgress.done()
                let prefix = Vue.prototype.$appBasePath
                if (this.to.path.includes(prefix)) {
                    let path = this.to.path.replace(prefix, '')
                    this.next({ path: path, query: { ...this.to.query, keepOrigin: true }, params: this.to.params, meta: this.to.meta, replace: true })
                }
                else {
                    this.next()
                }
            }
        })
    }
}
